#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <signal.h>
#include <netdb.h>
#include <string>
#include <pthread.h>

#include "definitions.hpp"

using namespace std;


void* tcp_thread_client_func(void* d2){
    //Data* d = (Data*) d1;
    int nsockfd, portno, n;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    portno = d1->getPortNum();
    unsigned char buffer[8];
    nsockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (nsockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname((char*)(d1->getHostname().c_str()));
    //cout<<"sockfd: "<<nsockfd<<endl;
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
          (char *)&serv_addr.sin_addr.s_addr,
          server->h_length);
    serv_addr.sin_port = htons(d1->getPortNum());
    if (connect(nsockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");
    //cout<<"message sending: "<<endl;
    bzero(buffer,8);
    uint64_t fSize;
    fSize = d1->getfileSize();
    //cout<<"FSize in tcp thread client"<<fSize<<endl;
    memcpy(buffer,&fSize,sizeof(fSize));
    n = write(nsockfd,buffer,8);
    if (n < 0) 
        error("ERROR writing to socket");
    bzero(buffer,sizeof(buffer));
    n = read(nsockfd,buffer,4);
    if (n < 0) 
        error("ERROR reading from socket");
    //cout<<"sockfd2: "<<nsockfd<<endl;
    
    complete_flag=0;
    
    
    // Create UDP thread to send UDP Duplicates
    
    pthread_t udp_dup_thread;
    pthread_attr_t attr_udp_dup;
    int thrd_udp_dup=0;
    // void* status_udp_dup;
    
    int overhead=0;
    
    pthread_attr_init(&attr_udp_dup);
    pthread_attr_setdetachstate(&attr_udp_dup, PTHREAD_CREATE_JOINABLE);
    //cout<<"Before pthread create udpSFASFDAFD"<<endl;
    thrd_udp_dup=pthread_create(&udp_dup_thread,&attr_udp_dup,udp_thread_duplicate_client_func,(void *)overhead);
    if(thrd_udp_dup){
        cerr<<"Error; return code from thread tcp create call is"<<thrd_udp_dup<<endl;
        exit(-1);
    } 
    
    pthread_attr_destroy(&attr_udp_dup);
    
    
    
    
    //
    while(complete_flag!=1){       
        //  bzero(dupBuffer1,2500);
        if(sock_ready_client(nsockfd)){
            //cout<<"before read"<<endl;
			unsigned char* ptr1 = new unsigned char[2];
			n = read(nsockfd,ptr1,1);
			if(n<=0){
				//error("ERROR reading from socket for Duplicates");
				error("tcp read"); 
                continue;
			}
            complete_flag = 1;
            pthread_mutex_lock(&dup_lock);
            pthread_cond_signal(&dup_cond);
            pthread_mutex_unlock(&dup_lock);
            
            
        }
        else{
            continue;
        }              
    }
    pthread_mutex_lock(&dup_lock);
    pthread_cond_signal(&dup_cond);
    pthread_mutex_unlock(&dup_lock);
    close(nsockfd);  
    //pthread_kill();
    //cout<<"tcp_thread_client exiting"<<endl;
    pthread_exit(NULL);
}

